package org.ndx.majick.properties;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;

import org.ndx.majick.properties.util.PropertyUtils;

/**
 * Experience bean, used to try all sort of things
 * @author Nicolas Delsaux
 */
public class Experience {
	public static final String NAME = Experience.class.getName()+".name";

	public static enum State {
		SENT, NOTSENT
	}
    /**
     * Experience is a bean, it'll fire events, thanks to this support
     */
    protected transient final PropertyChangeSupport support = new PropertyChangeSupport(this);
    /**
     * Experience is a bean, it'll allow vetoable events, thanks to this support
     */
    protected transient final VetoableChangeSupport vetoSupport = new VetoableChangeSupport(this);
    /**
     * A simple unconstrainted name property should be easily understood by anybody
     */
    private final ComparableProperty<String> nameProperty = PropertyUtils.create(String.class, NAME, support);

    /**
     * A constrainted id property should be easily understood by anybody
     */
    private final ComparableVetoableProperty<String> idProperty = PropertyUtils.create(String.class, Experience.class.getName()+".id", support, vetoSupport);

    /**
     * A constrained double property could allow external code to prevent it from having certain values (see in tests for examples)
     */
    private final ComparableVetoableProperty<Double> valueProperty = PropertyUtils.create(Double.class, Experience.class.getName()+".value", support, vetoSupport, 0.0);
    
    private final ComparableProperty<Integer> indexProperty = PropertyUtils.create(Integer.class, Experience.class+".index", support, 0);

    private final Property<Boolean> activeProperty = PropertyUtils.create(Boolean.class, Experience.class.getName()+".active", support);
    
    private final VetoableProperty<Boolean> importantProperty = PropertyUtils.create(Boolean.class, Experience.class.getName()+".important", support, vetoSupport);
    
    private final Property<State> stateProperty = PropertyUtils.create(State.class, Experience.class.getName()+".state", support);
    
    public ComparableVetoableProperty<Double> getValueProperty() {
        return valueProperty;
    }

    public ComparableProperty<String> getNameProperty() {
        return nameProperty;
    }
    
    /**
     * Name setter.
     * Defining a setter is not at all required, nor it is even needed. However, it can be of some use when working on beans where an internal state has to be maintained : it avoids the need for internal PropertyChangeListeners).
     * @param name
     * @category setter
     */
    public void setName(String name) {
        nameProperty.set(name);
    }
    
    public String getName() {
        return nameProperty.get();
    }
    
    public void setValue(double value) {
        valueProperty.set(value);
    }
    
    public double getValue() {
        return valueProperty.get();
    }

    public synchronized void removeVetoableChangeListener(VetoableChangeListener listener) {
        vetoSupport.removeVetoableChangeListener(listener);
    }

    public synchronized void addVetoableChangeListener(VetoableChangeListener listener) {
        vetoSupport.addVetoableChangeListener(listener);
    }

    public synchronized void removePropertyChangeListener(PropertyChangeListener listener) {
        support.removePropertyChangeListener(listener);
    }

    public synchronized void addPropertyChangeListener(PropertyChangeListener listener) {
        support.addPropertyChangeListener(listener);
    }

	public ComparableVetoableProperty<String> getIdProperty() {
		return idProperty;
	}
	
	public void setId(String value) {
		idProperty.set(value);
	}
	
	public String getId() {
		return idProperty.get();
	}

	public Property<Boolean> getActiveProperty() {
		return activeProperty;
	}

	public VetoableProperty<Boolean> getImportantProperty() {
		return importantProperty;
	}

	public ComparableProperty<Integer> getIndexProperty() {
		return indexProperty;
	}

	public Property<State> getStateProperty() {
		return stateProperty;
	}
}
